package com.gcs.application.gui.views;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.net.URL;
import java.util.ArrayList;
import java.util.Timer;
import java.util.TimerTask;

import org.eclipse.core.runtime.FileLocator;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.CTabFolder;
import org.eclipse.swt.custom.CTabItem;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.part.ViewPart;

import BISTel.PeakPerformance.SECSParser.SECSMessage;

import com.gcs.application.gui.Activator;

public class MessageRuntimeView extends ViewPart {
	class TreeObject {
		private final String name;
		private TreeParent parent;

		public TreeObject(String name) {
			this.name = name;
		}

		public String getName() {
			return this.name;
		}

		public TreeParent getParent() {
			return this.parent;
		}

		public void setParent(TreeParent parent) {
			this.parent = parent;
		}

		@Override
		public String toString() {
			return getName();
		}
	}

	@SuppressWarnings("unchecked")
	class TreeParent extends TreeObject {
		@SuppressWarnings("rawtypes")
		private final ArrayList children;

		@SuppressWarnings("rawtypes")
		public TreeParent(String name) {
			super(name);
			this.children = new ArrayList();
		}

		public void addChild(TreeObject child) {
			this.children.add(child);
			child.setParent(this);
		}

		public TreeObject[] getChildren() {
			return (TreeObject[]) this.children
					.toArray(new TreeObject[this.children.size()]);
		}

		public boolean hasChildren() {
			return this.children.size() > 0;
		}
	}

	class ViewContentProvider implements IStructuredContentProvider,
			ITreeContentProvider {

		@Override
		public void dispose() {
		}

		@Override
		public Object[] getChildren(Object parent) {
			if (parent instanceof TreeParent) {
				return ((TreeParent) parent).getChildren();
			}
			return new Object[0];
		}

		@Override
		public Object[] getElements(Object inputElement) {
			return getChildren(inputElement);
		}

		@Override
		public Object getParent(Object element) {
			if (element instanceof TreeObject) {
				return ((TreeObject) element).getParent();
			}
			return null;
		}

		@Override
		public boolean hasChildren(Object parent) {
			if (parent instanceof TreeParent) {
				return ((TreeParent) parent).hasChildren();
			}
			return false;
		}

		@Override
		public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
		}
	}

	class ViewLabelProvider extends LabelProvider {
		@Override
		public Image getImage(Object obj) {
			String imageKey = ISharedImages.IMG_OBJ_ELEMENT;
			if (obj instanceof TreeParent) {
				return Activator.getImageDescriptor("icons/SF.gif")
						.createImage();
			}
			return PlatformUI.getWorkbench().getSharedImages()
					.getImage(imageKey);
		}

		@Override
		public String getText(Object obj) {
			return obj.toString();
		}
	}

	public static final String ID = MessageRuntimeView.class.getName();
	public static final String Title = "Message Runtime View";
	private Button btnLoadFile, btnCreateMessage, btnSendMessage;
	private Button ckbPerformance;

	private Composite compMessages, compFreeMessage;

	private int iCount = 1000;
	private int iCountTemp = 0;

	private final int iDelay = 1000;
	private Label lblDelay, lblCount;
	private String messageName;
	private String pathFile = "";

	private SECSMessage secsMessage;

	private final ArrayList<Object> smlMessages = new ArrayList<Object>();
	private CTabFolder tabFolder;
	private CTabItem tabFreeMessage;
	private CTabItem tabMessages;
	private Timer timer;

	private Tree treeMessage;

	private TreeObject[] treeObject;

	private TreeViewer treeViewer;

	private Text txtMessage, txtDelay, txtCount;

	private void addButton() {
		// Create the grid data
		GridData gridData = new GridData();
		gridData.horizontalSpan = 4;
		gridData.horizontalAlignment = GridData.BEGINNING;
		gridData.heightHint = 23;

		// Add button into the tab Messages
		this.btnLoadFile = new Button(this.compMessages, SWT.PUSH); // this.form.getBody(),
																	// SWT.PUSH);
		this.btnLoadFile.setText("Load file");
		this.btnLoadFile.setLayoutData(gridData);
		this.btnLoadFile.addSelectionListener(new SelectionListener() {

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}

			@Override
			public void widgetSelected(SelectionEvent e) {
				FileDialog dialog = new FileDialog(compMessages.getShell(),
						SWT.OPEN);

				if (ConnectionView.device != null) {
					pathFile = dialog.open();

					if (pathFile.length() > 0) {
						ConnectionView.device.OpenSml(pathFile);
						showSECSMessage();
					}

					if (smlMessages.size() > 0) {
						treeViewer.setInput(createMessageModel());
						treeViewer.refresh(true);
					}
				} else {
					MessageDialog.openInformation(compMessages.getShell(),
							"Information",
							"Must create connection before load file sml.");
				}

			}
		});
		this.ckbPerformance = new Button(this.compMessages, SWT.CHECK);
		this.lblCount = new Label(this.compMessages, SWT.NONE);
		this.txtCount = new Text(this.compMessages, SWT.NONE);
		this.lblDelay = new Label(this.compMessages, SWT.NONE);
		this.txtDelay = new Text(this.compMessages, SWT.NONE);

		// Set properties for the check box Performance.
		this.ckbPerformance.setLayoutData(gridData);
		this.ckbPerformance.setSelection(false);
		this.ckbPerformance.setText("Performance");
		this.ckbPerformance.addSelectionListener(new SelectionListener() {

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}

			@Override
			public void widgetSelected(SelectionEvent e) {
				checkStatusPerformance();
			}
		});

		gridData = new GridData();
		gridData.widthHint = 80;

		this.lblCount.setText("Quantity:");
		this.txtCount.setText(String.valueOf(this.iCount));
		this.txtCount.setLayoutData(gridData);

		this.lblDelay.setText("Delay:");
		this.txtDelay.setText(String.valueOf(this.iDelay));
		this.txtDelay.setLayoutData(gridData);

		// Add button into the tab Free Message
		this.btnCreateMessage = new Button(this.compFreeMessage, SWT.PUSH);
		this.btnCreateMessage.setText("Create Message");
		this.btnCreateMessage.addSelectionListener(new SelectionListener() {

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}

			@Override
			public void widgetSelected(SelectionEvent e) {
				if (txtMessage.getText().length() > 0
						&& !txtMessage.getText().isEmpty()) {
					try {
						secsMessage = new SECSMessage(txtMessage.getText());

						MessageDialog.openInformation(
								compFreeMessage.getShell(), "Information",
								"The creating message is successful. \n");
					} catch (Exception ex) {
						MessageDialog.openError(
								compFreeMessage.getShell(),
								"Error",
								"The creating message is unsuccessful. \n"
										+ ex.getMessage());
					}
				}
			}
		});

		this.btnSendMessage = new Button(this.compFreeMessage, SWT.PUSH);
		this.btnSendMessage.setText("Send Message");
		this.btnSendMessage.addSelectionListener(new SelectionListener() {

			@Override
			public void widgetDefaultSelected(SelectionEvent e) {
			}

			@Override
			public void widgetSelected(SelectionEvent e) {
				if (secsMessage != null && ConnectionView.device != null) {
					ConnectionView.device.Send(secsMessage);
				}
			}
		});

		this.txtMessage = new Text(this.compFreeMessage, SWT.MULTI);
		GridData data = new GridData(GridData.FILL_BOTH);
		data.horizontalSpan = 2;
		this.txtMessage.setLayoutData(data);
	}

	private void addTreeViewer() {
		/*
		 * this.treeMessage = this.toolkit.createTree(this.composite,
		 * SWT.MULTI); this.treeMessage.setLayoutData(new
		 * GridData(GridData.FILL_BOTH));
		 */
		GridData gridData = new GridData(GridData.FILL_BOTH);
		gridData.horizontalSpan = 4;

		this.treeMessage = new Tree(this.compMessages, SWT.MULTI);
		this.treeMessage.setLayoutData(gridData);

		this.treeViewer = new TreeViewer(this.treeMessage);// this.treeMessage);
		this.treeViewer.setContentProvider(new ViewContentProvider());
		this.treeViewer.setLabelProvider(new ViewLabelProvider());
		this.treeViewer.setData(FormToolkit.KEY_DRAW_BORDER,
				FormToolkit.TEXT_BORDER);
		this.treeViewer.addDoubleClickListener(new IDoubleClickListener() {
			@Override
			public void doubleClick(DoubleClickEvent event) {
				String msgName = event.getSelection().toString();
				msgName = msgName.substring(1, msgName.length() - 1);

				sendMessage(msgName);
			}
		});
	}

	private void checkStatusPerformance() {
		if (ckbPerformance.getSelection()) {
			lblCount.setEnabled(true);
			txtCount.setEnabled(true);
			lblDelay.setEnabled(true);
			txtDelay.setEnabled(true);
		} else {
			lblCount.setEnabled(false);
			txtCount.setEnabled(false);
			lblDelay.setEnabled(false);
			txtDelay.setEnabled(false);
		}
	}

	private TreeObject createMessageModel() {
		TreeParent root = new TreeParent("");

		createTreeObject();

		for (TreeObject treeObject : this.treeObject) {
			root.addChild(treeObject);
		}

		return root;
	}

	@Override
	public void createPartControl(Composite parent) {
		this.tabFolder = new CTabFolder(parent, SWT.BORDER);

		this.compMessages = new Composite(this.tabFolder, SWT.NONE);
		GridLayout layout = new GridLayout(4, false);
		this.compMessages.setLayout(layout);

		this.compFreeMessage = new Composite(this.tabFolder, SWT.NONE);
		layout = new GridLayout(2, true);
		this.compFreeMessage.setLayout(layout);

		this.tabFreeMessage = new CTabItem(this.tabFolder, SWT.NONE);
		this.tabFreeMessage.setText("Free Message");
		this.tabFreeMessage.setControl(this.compFreeMessage);

		this.tabMessages = new CTabItem(this.tabFolder, SWT.NONE);
		this.tabMessages.setText("Messages");
		this.tabMessages.setControl(this.compMessages);

		// Load the SML file
		try {
			URL fileURL = FileLocator.find(Platform
					.getBundle("SECSTestApplication"), new Path(
					"/sml/message.sml"), null);
			fileURL = FileLocator.toFileURL(fileURL);
			this.pathFile = fileURL.getPath();
		} catch (IOException ex) {
			System.err.println(ex.getMessage());
		}

		// Set controls into the form
		addButton();
		addTreeViewer();

		// Check the performance status
		checkStatusPerformance();

		this.tabFolder.setSelection(0);
	}

	private void createTreeObject() {
		String message = "";
		if (this.smlMessages.size() > 0) {
			this.treeObject = new TreeObject[this.smlMessages.size()];
			for (int index = 0; index < this.smlMessages.size(); index++) {
				message = this.smlMessages.get(index).toString();

				if (message.length() > 0) {
					this.treeObject[index] = getDataType(message);
				}
			}
		}
	}

	private TreeObject getDataType(String message) {
		String name = "";
		String messageHeader;
		int index = 0;
		@SuppressWarnings("unused")
		int offset = 0;

		TreeParent parent = new TreeParent("");
		@SuppressWarnings("unused")
		TreeObject child;

		if (message.indexOf(':') > 0 || message.indexOf('S') > 0
				|| message.indexOf('s') > 0 || message.indexOf('<') > 0
				|| message.indexOf('.') > 0) {
			offset = 0;

			if (message.indexOf(" <R> ") > 0)
				message = message.replaceAll("<R>", "");
			if (message.indexOf("H<-E") > 0)
				message = message.replaceAll("H<-E", "");
			else if (message.indexOf("H->E") > 0)
				message = message.replaceAll("H->E", "");
			else if (message.indexOf("H->E") > 0)
				message = message.replaceAll("H<->E", "");

			index = message.indexOf('<');
			if (index > 0) {
				offset = index;
				messageHeader = message.substring(0, index);
			} else {
				messageHeader = message;
			}

			messageHeader = removeDelimiters(messageHeader);

			index = messageHeader.indexOf(':');
			if (index > 0) // name: SxFy
			{
				name = messageHeader.substring(0, index);
				parent = new TreeParent(name);
			} else { // SxFy | 'SxFy'
				index = messageHeader.indexOf(' ');
				if (index > 0) {
					name = messageHeader.substring(0, index);
					parent = new TreeParent(name);
				} else {
					name = messageHeader.trim();
					parent = new TreeParent(name);
				}

				if (name.startsWith("'")) {
					name = name.substring(1, name.length() - 1);
					messageHeader = name;
					parent = new TreeParent(name);
				}
			}
		}
		return parent;
	}

	protected void readSMLFile(String fileName) {
		try {
			File file = new File(fileName);
			if (file.exists()) {
				FileReader reader = new FileReader(file);
				LineNumberReader lineLeader = new LineNumberReader(reader);

				String text;
				String message = "";
				do {
					text = lineLeader.readLine();
					if (text != null) {
						if (text.length() > 0 && text.startsWith("*") == false) {
							char firstChar = text.charAt(0);
							if (firstChar != ' ' && firstChar != '\t'
									&& firstChar != '<' && firstChar != '>') {
								if (message.length() == 0)
									message = text;
								else {
									this.smlMessages.add(message);
									message = "";
									if (text.length() > 2
											&& text.substring(0, 3)
													.toUpperCase() == "IF ") {
										text = null;
										break;
									} else
										message = text;
								}
							} else {
								message += text;
							}
						}
					}
				} while (text != null);
				if (message.length() > 0)
					this.smlMessages.add(message);
				lineLeader.close();
				reader.close();
			}
		} catch (IOException ex) {
			ex.printStackTrace();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
	}

	private String removeDelimiters(String text) {
		return text.replace('\t', ' ').replace('\r', ' ').replace('\n', ' ')
				.trim();
	}

	private void sendMessage(String msgName) {
		if (!this.ckbPerformance.getSelection()) {
			if (ConnectionView.device != null) {
				ConnectionView.device.Send(ConnectionView.device
						.GetSECSMessage(msgName.trim()));
			}
		} else {
			try {
				// Set value into the global variables
				this.iCount = Integer.parseInt(txtCount.getText());
				this.messageName = msgName;

				this.timer = new Timer();
				TimerTask timerTask = new TimerTask() {

					@Override
					public void run() {
						if (iCountTemp < iCount) {
							iCountTemp++;
							if (messageName.length() > 0) {
								ConnectionView.device
										.Send(ConnectionView.device
												.GetSECSMessage(messageName
														.trim()));
							}
						} else {
							iCountTemp = 0;
							messageName = "";
							this.cancel();
						}
					}
				};
				this.timer.scheduleAtFixedRate(timerTask, 1000,
						Integer.parseInt(this.txtDelay.getText()));
			} catch (Exception ex) {
				ex.printStackTrace();
			}
		}
	}

	@Override
	public void setFocus() {
		this.tabFolder.setFocus();
	}

	public void showSECSMessage() {

		// emvlm: it should get from list SECSMessage until empty, shouldn't
		// hard code 100 length
		int autoLength = 100;
		this.smlMessages.clear();

		for (int index = 0; index < autoLength; index++) {
			if (ConnectionView.device.GetSECSMessage(index) == null) {
				break;
			} else {
				this.smlMessages.add(ConnectionView.device
						.GetSECSMessage(index).ToSml());
			}
		}
	}
}
